package com.block.common.annotate.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;

import com.block.common.annotate.ExceptionLog;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.service.LogFactory;
import com.block.common.util.SpelUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 异常统一处理中心
 * 
 */
@Aspect
@Component
public class ExceptionLogAspect {

    private NotifyExceptionService notifyExceptionService;

    @Autowired
    public void setNotifyExceptionService(NotifyExceptionService notifyExceptionService) {
        this.notifyExceptionService = notifyExceptionService;
    }

    private static Logger logger = LogFactory.getErrorInfoLog();


    @Around("@annotation(exceptionLog)")
    public Object doAround(ProceedingJoinPoint pjp, ExceptionLog exceptionLog) throws Throwable, Exception {
        String key = exceptionLog.key();
        String bizName = exceptionLog.bizName();
        String flowno = SpelUtil.getParams(pjp, key);
        boolean toDb = exceptionLog.toDb();
        String bizType = exceptionLog.bizType();
        String bizFlowno = flowno;
        if (!StrUtil.isEmpty(bizName)) {
            bizFlowno = bizName + flowno;
        }
        // target class
        Class<?> targetClass = pjp.getTarget().getClass();
        // method name
        String methodName = pjp.getSignature().getName();
        // parameter types
        Class<?>[] parameterTypes = ((MethodSignature) pjp.getSignature()).getMethod().getParameterTypes();
        // method
        Method method = targetClass.getMethod(methodName, parameterTypes);
        // arguments
        Object[] arguments = pjp.getArgs();

        try {
            return pjp.proceed();
        } catch (Exception e) {
            Class<? extends Throwable>[] throwables = exceptionLog.noNotifybackFor();

            if (throwables == null || throwables.length <= 0) {
                notifyExceptionService.notifyException(bizFlowno, targetClass.getName(), methodName, parameterTypes, arguments, e);
            } else {
                //将class转为className
                List<String> list = CollUtil.newArrayList(throwables).stream().map(clazz -> clazz.getName()).collect(Collectors.toList());
                //如果不存在 则进行日志处理
                if (!list.contains(e.getClass().getName())) {
                    notifyExceptionService.notifyException(bizFlowno, targetClass.getName(), methodName, parameterTypes, arguments, e);

                }
            }
            if (toDb) {
                boolean saveResult = notifyExceptionService.saveException(bizType, flowno, bizFlowno, targetClass.getName(), methodName, e);
                logger.info("保存异常信息结果:{},bizType:{},key:{},flowno:{},methodName:{}", saveResult, bizType, key, flowno, methodName);
            }
            throw e;
        } catch (Throwable throwable) {
            notifyExceptionService.notifyException(flowno, targetClass.getName(), methodName, parameterTypes, arguments, throwable);
            throw throwable;
        }
    }


}
